
#ifndef __COID_SERVER_TUNNELMGR__HEADER_FILE__
#define __COID_SERVER_TUNNELMGR__HEADER_FILE__

#include "coid/svc/coidsvc.h"
#include "coid/comm/alloc/chunkalloc.h"

#include "coid/comm/binstream/inoutstream.h"
#include "coid/comm/metastream/fmtstreamcxx.h"
#include "coid/comm/metastream/fmtstreamjson.h"
#include "coid/comm/metastream/fmtstreamxml.h"
#include "coid/comm/binstream/httpstreamtunnel.h"


namespace coid {

////////////////////////////////////////////////////////////////////////////////
///COID http tunneling gateway
class TunnelMgr
{
    //NET_OPTIONS: nolog nolog_system_calls direct interprocess
    cmd_interface* _cmdin;

public:

    TunnelMgr()
    {
    }

    ~TunnelMgr()
    {
    }

    // special functions
    net_fnc_s opcd accept_connect( net_account account_id& acid )
    {
        return 0;
    }

    net_fnc_s opcd accept_startup_params( cmd_interface& cmd )
    {
        _cmdin = &cmd;
        return 0;
    }
    
    net_fnc_s opcd accept_connect_shared()
    {
        return ersDENIED;
    }

    ///Process incomming tunnel requests
    net_fnc_d opcd process_tunnel( httpstreamcoid::header& hdr, cachestream& net, netAddress& addr );

	///Process incomming http call requests
	net_fnc_d opcd process_local_call( httpstreamcoid& net, token qry, netAddress& addr );

	///Process remote...
	net_fnc opcd process_remote_call(
		net_inout dynarray<uchar>& buf, 
		const charstr& qry, 
		netAddress& addr, 
		net_inout uint64& ssid, 
		net_out charstr& contentType );

	///Process remote soap call...
	net_fnc opcd process_remote_soap_call(
		net_inout dynarray<uchar>& buf, 
		net_in charstr& service,
		netAddress& addr, 
		net_inout uint64& ssid );

	///Process loacl soap call...
	net_fnc_d opcd process_local_soap_call(
		httpstreamcoid& net, 
		charstr& service,
		netAddress& addr, 
		uint64& ssid );

private:
    struct record;

    opcd process_generic_open( httpstreamcoid::header& hdr, cachestream& net, netAddress& addr );

    opcd verify_ssid( uint64 ssid, record** pp );
    opcd execute( uint64 ssid, uint mid, binstream& bin, netAddress& addr, metastream* meta );
    opcd execute( record* p, uint mid, binstream& bin, netAddress& addr, metastream* meta );
    opcd execute( record* p, token meth, binstream& bin, netAddress& addr, metastream* meta );

    opcd qry_services( token svc, metastream& meta );
    opcd qry_methods( token svcver, metastream& meta );
    opcd qry_types( token svcver, const token& type, metastream& meta );

    uint64 create_slot()
    {
        record* p = get_schm().alloc();
        return p->generate_ssid();
    }

    const dynarray<ServiceDescriptor::MethodDesc::Arg>& memberinfo( const MetaDesc* desc )
    {
        _memberinfo.reset();
        return memberinfo_append(desc);
    }

    const dynarray<ServiceDescriptor::MethodDesc::Arg>& memberinfo_append( const MetaDesc* desc )
    {
        uints n = desc->children.size();
        ServiceDescriptor::MethodDesc::Arg* mi = _memberinfo.add(n);

        for( uints i=0; i<n; ++i )
        {
            mi[i].meta.reset();
            desc->children[i].type_string( mi[i].meta );

            mi[i].name = desc->children[i].varname;
            mi[i].type.reset();
        }

        return _memberinfo;
    }

	opcd process_call( binstream& net, token qry, netAddress& addr, 
		uint64& ssid, charstr& content_type, bool local_call);

private:
    struct record
    {
        uint64 _ssid;               ///< session id
        uint  _soid;                ///< server object id

        record()
        {
            _ssid = 0;
            _soid = UMAX32;
        }

        uint64 generate_ssid();

        bool is_object_valid() const        { return _soid != UMAX32; }

        static record* get_from_ssid( uint64 ssid )
        {
            return (record*)( (uint)(ssid>>32) ^ (uint)ssid );
        }
    };

    static chunk_allocator<record>& get_schm()
    {
        static chunk_allocator<record> _schm;
        return _schm;
    }


    metastream _meta;

    fmtstreamcxx _fmtcxxo;
    fmtstreamcxx _fmtcxxi;
    fmtstreamjson _fmtjson;
    fmtstreamxml _fmtxml;

    dynarray<ServiceDescriptor::MethodDesc::Arg> _memberinfo;
};

} // namespace coid

#endif //__COID_SERVER_TUNNELMGR__HEADER_FILE__
